import * as fs from "fs";
import * as child_process from "child_process";
import * as inquirer from "inquirer";
import * as util from "util";
//import * as chalk from "chalk";
// @ts-ignore
import semverInc from "semver/functions/inc";
import {ReleaseType} from 'semver';
import * as path from 'path';

// @ts-ignore
import  pkg from '../package.json';

const exec = util.promisify(child_process.exec);

const run = async (command: string) => {
    console.log(command);
    await exec(command);
};

const currentVersion = pkg.version;

const getNextVersions = (): { [key in ReleaseType]: string | null } => ({
    major: semverInc(currentVersion, 'major'),
    minor: semverInc(currentVersion, 'minor'),
    patch: semverInc(currentVersion, 'patch'),
    premajor: semverInc(currentVersion, 'premajor'),
    preminor: semverInc(currentVersion, 'preminor'),
    prepatch: semverInc(currentVersion, 'prepatch'),
    prerelease: semverInc(currentVersion, 'prerelease'),
})

const timeLog = (logInfo: string, type: 'start' | 'end') => {
    let info = '';
    if (type === 'start') {
        info = `=> 开始任务：${logInfo}`;
    } else {
        info = `✨ 结束任务：${logInfo}`;
    }
    const nowDate = new Date();
    console.log(
        `[${nowDate.toLocaleString()}.${nowDate.getMilliseconds().toString().padStart(3, '0')}] ${info}`,
    );
};

function getValidKey(key: string, obj: { [key in ReleaseType]: string | null }) {
    // @ts-ignore
    return key in obj ? obj[key] :''
}

// @ts-ignore
async function prompt(): Promise {
    const nextVersions = getNextVersions();
    // @ts-ignore
    const {nextVersion} = await inquirer.prompt([
        {
            type: 'list',
            name: 'nextVersion',
            message: `请选择将要发布的版本 (当前版本 ${currentVersion})`,
            choices: (Object.keys(nextVersions)).map((level) => ({
                name: `${level} => ${getValidKey(level,nextVersions)}`,
                value: getValidKey(level,nextVersions),
            })),
        },
    ]);
    return nextVersion;
}

async function updateVersion(nextVersion: string) {
    pkg.version = nextVersion;
    timeLog('修改package.json版本号', 'start');
    await fs.writeFileSync(path.resolve(__dirname, './../package.json'), JSON.stringify(pkg));
    await run('npx prettier package.json --write');
    timeLog('修改package.json版本号', 'end');
}

async function generateChangelog() {
    timeLog('生成CHANGELOG.md', 'start');
    await run('conventional-changelog -p angular -i CHANGELOG.md -s -r 0');
    timeLog('生成CHANGELOG.md', 'end');
}

async function push(nextVersion: string) {
    timeLog('推送代码至git仓库', 'start');
    await run('git add package.json CHANGELOG.md');
    await run(`git commit -m "v${nextVersion}" -n`);
    await run('git push');
    timeLog('推送代码至git仓库', 'end');
}

async function build() {
    timeLog('组件库打包', 'start');
    await run('yarn build');
    timeLog('组件库打包', 'end');
}

async function publish() {
    timeLog('发布组件库', 'start');
    await run('npm publish');
    timeLog('发布组件库', 'end');
}

async function tag(nextVersion: string) {
    timeLog('打tag并推送至git', 'start');
    await run(`git tag v${nextVersion}`);
    await run(`git push origin tag v${nextVersion}`);
    timeLog(`打tag并推送至git`, 'end');
}


async function main() {
    try {
        const nextVersion = await prompt();
        const startTime = Date.now();
        // =================== 更新版本号 ===================
        await updateVersion(nextVersion);
        // =================== 更新changelog ===================
        await generateChangelog();
        // =================== 代码推送git仓库 ===================
        await push(nextVersion);
        // =================== 组件库打包 ===================
        await build();
        // =================== 发布至npm ===================
        await publish();
        // =================== 打tag并推送至git ===================
        await tag(nextVersion);
        console.log(`✨ 发布流程结束共耗时${((Date.now() - startTime) / 1000).toFixed(3)}s`);
    } catch (error) {
        console.log('💣 发布失败，失败原因：', error);
    }
}

main();
